#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include "config.h"

time_t czas_utw;
int exited = 0;

void sigtstp(
#ifdef SIGNAL
	int signal
#endif	
	) {
	int czas = (int)(time(NULL) - czas_utw);
	printf("Otrzymałem SIGTSTP, mój PID = %d istnieje od %d sekund\n", getpid(), czas); 
	exited = 1;
	_exit(czas);
}

void sigchld(
#ifdef SIGNAL
	int signal
#endif
	) {
	int status;
	pid_t child_pid = wait(&status);
	printf("Mój potomek o PID = %d zakończył swój żywot. ", child_pid);
	printf("Kod zakończenia: %d\n", WEXITSTATUS(status));
}

int main(int argc, char ** argv) {
#if defined SIGNAL || defined SIGNALACT
	if (argc != 2) {
		printf("Zła liczba argumentów. Poprawne wywołanie: ./zad1.o <liczba>\n");
		return -1;
	}
	int i, count = atoi(argv[1]);
	if (count <= 0) {
		printf("W pierwszym argumencie musi być liczba całkowita dodatnia!\n");
		return -2;
	}
	pid_t pidy[count], pid_parent = getpid();
	printf("Parent PID = %d\n",(int)pid_parent);
#ifdef SIGNAL
	if (signal(SIGCHLD, sigchld) == SIG_ERR) {
		perror("signal");
		return -3;
	}
#else
	struct sigaction act, oldact;
	act.sa_handler = sigchld;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);
	if (sigaction(SIGCHLD, &act, &oldact) < 0 ){
		perror("sigaction SIGCHLD");
		return -5;
	}
	
#endif
	srand(time(NULL));
	for(i = 0; i < count; i++) {
		if ((pidy[i] = fork()) < 0) {	//błąd forka
			perror("fork");
			return -3;
		} else if (pidy[i] == 0) {		//potomek ustawienie funkcji obsługi
			printf("Jestem nowy. Mój pid = %d\n", (int)getpid());
			fflush(stdout);
			czas_utw = time(NULL);
		#ifdef SIGNAL
			if (signal(SIGTSTP, sigtstp) == SIG_ERR) {
				perror("signal");
				return -4;
			}
		#else
			struct sigaction childact, childoldact;
			childact.sa_handler = sigtstp;
			childact.sa_flags = 0;
			sigemptyset(&childact.sa_mask);
			if (sigaction(SIGTSTP, &childact, &childoldact) < 0 ){
				perror("sigaction SIGTSTP");
				return -6;
		}
		#endif
			while(exited == 0){
				;
			}
		} else {
			usleep(100000);
		}
	}
	if (getpid() == pid_parent) {
		for (;;) {
			int which = rand() % count;
			printf("Wylosowano: %d %d\n", which, (int)pidy[which]);
			kill(pidy[which], SIGTSTP);
			sleep(3);
			if ((pidy[which] = fork()) < 0){
				perror("fork");
				return -4;
			} else if (pidy[which] == 0) {
				printf("Jestem nowy. Mój pid = %d\n", (int)getpid());
				czas_utw = time(NULL);
			#ifdef SIGNAL
				signal(SIGTSTP, sigtstp);
			#else
				struct sigaction childact, childoldact;
				childact.sa_handler = sigtstp;
				childact.sa_flags = 0;
				sigemptyset(&childact.sa_mask);
				if (sigaction(SIGTSTP, &childact, &childoldact) < 0 ){
					perror("sigaction SIGTSTP");
					return -6;
				}
			#endif
				while(exited == 0){
					;
				}
			}
			sleep(4);
		}
	}
	return 0;
#else
	printf("Błędna próba kompilacji. Poprawna kompilacja: ./configure --with-handler={SIGNAL, SIGNALACT} & make\n");
	return -1;
#endif
}
